/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	ComponentContainer.cpp
*
*	Comments	-	See ComponentContainer.h
*
**************************************************************************************/
#include "../Include/ComponentContainer.h"
#include "../Include/FactoryComponent.h"

namespace Pulse
{
	ComponentContainer::ComponentContainer( void )
	{
	}

	ComponentContainer::~ComponentContainer( void )
	{
		ClearComponents();
	}

	void ComponentContainer::Update( FLOAT dt )
	{
		for ( SIZE_T i = 0; i < m_components.GetSize(); ++i )
		{
			m_components[i]->Update( dt );
		}
	}

	IComponent * ComponentContainer::AddComponent( EComponent::Type type, Actor *pOwner, XMLElementPtr pElem )
	{
		auto findIter = m_componentMap.Find( type );

		if ( findIter != m_componentMap.IteratorEnd() )
		{
			PSX_PushWarning( "Component type already exists. Returning existing component." );
			return findIter->second;
		}

		// Create new component 
		IComponent *pNewComponent = FactoryComponent::GetInstance()->Create( type, pOwner );
		
		if ( pNewComponent == PSX_NULL )
		{
			return PSX_NULL;
		}

		// then add it to the map and list
		m_componentMap[type] = pNewComponent;
		m_components.PushBack( pNewComponent );

		pNewComponent->Initialize( pElem );

		return pNewComponent;
	}

	IComponent * ComponentContainer::GetComponent( EComponent::Type componentType )
	{
		auto findIter = m_componentMap.Find( componentType );

		if ( findIter != m_componentMap.IteratorEnd() )
		{
			return findIter->second;
		}
		else
		{
			return PSX_NULL;
		}
	}

	IComponent * ComponentContainer::GetComponent( const CHAR *pName )
	{
		for ( SIZE_T i = 0; i < m_components.GetSize(); ++i )
		{
			if ( PSX_StrCmp( m_components[i]->GetName(), pName ) == 0 )
			{
				return m_components[i];
			}
		}

		return PSX_NULL;
	}

	IComponent * ComponentContainer::GetComponent( EComponent::Type componentType, const CHAR *pName )
	{
		auto findIter = m_componentMap.Find( componentType );

		if ( findIter != m_componentMap.IteratorEnd() )
		{
			IComponent *pComponent = findIter->second;
			if ( PSX_StrCmp( pComponent->GetName(), pName ) == 0 )
			{
				return pComponent;
			}
		}
		
		return PSX_NULL;
	}

	BOOL ComponentContainer::RemoveComponent( EComponent::Type componentType )
	{
		auto findIter = m_componentMap.Find( componentType );

		if ( findIter != m_componentMap.IteratorEnd() )
		{
			IComponent *pComponent = findIter->second;
			m_componentMap.Remove( findIter );

			// Don't forget to remove it also in the list
			for ( SIZE_T i = 0; i < m_components.GetSize(); ++i )
			{
				if ( m_components[i] == pComponent )
				{
					m_components.Remove( i );
					break;
				}
			}

			// TODO: Pass this in factory for removal.
			delete pComponent;
			return TRUE;
		}
		
		return FALSE;
	}

	BOOL ComponentContainer::RemoveComponent( EComponent::Type componentType, const CHAR *pName )
	{
		auto findIter = m_componentMap.Find( componentType );

		if ( findIter != m_componentMap.IteratorEnd() )
		{
			IComponent *pComponent = findIter->second;

			// Check if its the same name
			if ( PSX_StrCmp( pComponent->GetName(), pName ) == 0 )
			{
				m_componentMap.Remove( findIter );

				// Don't forget to remove it also in the list
				for ( SIZE_T i = 0; i < m_components.GetSize(); ++i )
				{
					if ( m_components[i] == pComponent )
					{
						m_components.Remove( i );
						break;
					}
				}

				delete pComponent;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	void ComponentContainer::ClearComponents( void )
	{
		m_componentMap.Clear();

		for ( SIZE_T i = 0; i < m_components.GetSize(); ++i )
		{
			IComponent *pComponent = m_components[i];
			delete pComponent;
		}

		m_components.Clear();

	}

}